#include <QtGui>
#include <QFileDialog>
#include <QMessageBox>
#include <QApplication>
#include <QMediaPlayer>
#include <QMediaPlaylist>
#include <QVideoWidget>
#include <QVBoxLayout>
#include <QSystemTrayIcon>
#include <QMenu>
#include <QTimer>

#include <iostream>
#include <windows.h>
#include <stdio.h>

#include "widget.h"
#include "ui_widget.h"
#include "support.h"

//将child窗体设置为桌面的子窗体
bool SetBackground(HWND child);
//判断程序是否已经打开自启动
bool isAutoRun();
//获取桌面窗体
HWND GetBackground();

bool firstPlay = true;//判断是否是第一次加载视频，如果是则需要初始化播放器
int VolumeNowPic = 2;//当前音量图标，2,1,0分别表示“高”，“低”，“静音”
QString path = "";//视频文件地址
bool sliderEnable = true;//速度滑块的value_changed监听是否可用

Widget::Widget(QWidget *parent)
        : QWidget(parent), ui(new Ui::Widget) {
    ui->setupUi(this);
    ui->playButton->setEnabled(false);
    addMenu();
    ReadSetting();//读取设置
    about.SetFather(this);//给“关于”窗体设置父窗体
    if (ui->checkBox_2->isChecked()) {//是否开启了“加载上一次视频”
        LoadFile(path);//加载视频,path的值在ReadSetting()中读取
    }
    ui->checkBox_1->setChecked(isAutoRun());//是否开机自启
    ui->fileLabel->installEventFilter(this);//注册窗体最顶上的文件Label点击事件
    ui->volumePic->installEventFilter(this);//注册音量Label的点击事件
}

Widget::~Widget() {
    delete ui;
}

//添加任务栏角标
void Widget::addMenu(){
    tray.setToolTip("Wallpaper");//任务栏托盘小图标的标题
    tray.setIcon(QIcon(":Icon/wallpaper.ico"));//任务栏托盘小图标
    QMenu *menu = new QMenu();
    action_showDialog = new QAction("打开主窗口");
    action_play = new QAction("播放");
    action_play->setEnabled(false);
    action_exit = new QAction("退出");
    menu->addAction(action_showDialog);//添加菜单
    menu->addAction(action_play);//添加菜单
    menu->addSeparator();
    menu->addAction(action_exit);//添加菜单
    tray.setContextMenu(menu);//绑定菜单
    //绑定托盘小图标点击事件
    connect(&tray, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(OnSystemTrayClicked(QSystemTrayIcon::ActivationReason)));
    //绑定菜单点击事件
    connect(action_showDialog, SIGNAL(triggered(bool)), this, SLOT(onShowDialogClick()));
    connect(action_exit, SIGNAL(triggered(bool)), this, SLOT(on_exitButton_clicked()));
    connect(action_play,SIGNAL(triggered(bool)),this,SLOT(on_playButton_clicked()));
    tray.show();//显示小图标
}

//事件监听
bool Widget::eventFilter(QObject *obj, QEvent *event) {
    //文件Label被点击
    if (obj == ui->fileLabel && event->type() == QEvent::MouseButtonPress) {
        QMouseEvent *mouse = static_cast<QMouseEvent *>(event);
        if (mouse->button() == Qt::LeftButton && path != "") {
            //如果是左键，则打开文件位置
            QProcess process;
            QString p = path.replace("/", "\\");
            QString cmd = "explorer /select," + p;
            process.startDetached(cmd);
        }
    }
    //音量Label被点击
    if (obj == ui->volumePic && event->type() == QEvent::MouseButtonPress) {
        QMouseEvent *mouse = static_cast<QMouseEvent *>(event);
        if (mouse->button() == Qt::LeftButton) {
            if (player.volume() == 0) {
                //音量是0，恢复volumeSlider上的正常音量
                on_volumeSlider_valueChanged(ui->volumeSlider->value());
            } else {
                //音量不是0，静音
                player.setVolume(0);
                ui->volumePic->setStyleSheet(VOLUME_OFF);
                VolumeNowPic = 0;
            }
        }
    }
    return false;
}

//点击了“打开”按钮，打开文件
void Widget::on_openButton_clicked() {
    QString file = QFileDialog::getOpenFileName(
            this,
            "打开文件",
            path,//初始地址
            PLAYER_FILTER);//过滤器，仅显示支持的格式
    if (!file.isEmpty()) {
        LoadFile(file);
    }
}

//点击了任务栏托盘小图标
void Widget::OnSystemTrayClicked(QSystemTrayIcon::ActivationReason reason) {
    if (reason == QSystemTrayIcon::Trigger) {
        this->showNormal();//如果点击了任务栏托盘小图标，则显示本窗口
    }
}

//点击了菜单
void Widget::onShowDialogClick() {
    this->showNormal();//点击了“打开主窗口”，显示本窗口
}

//“播放”或者“暂停”按钮点击事件
void Widget::on_playButton_clicked() {
    if (ui->playButton->text().compare(BUTTON_TEXT_PLAY) == 0) {
        //点击了“播放”按钮，播放视频，并把按钮文本设置为“暂停”
        player.play();
        ui->playButton->setText(BUTTON_TEXT_PAUSE);
        action_play->setText(BUTTON_TEXT_PAUSE);
    } else {
        //点击了“暂停”按钮，暂停视频，并把按钮文本设置为“播放”
        player.pause();
        ui->playButton->setText(BUTTON_TEXT_PLAY);
        action_play->setText(BUTTON_TEXT_PLAY);
    }
}

//退出按钮点击事件，同时任务栏小图标的”退出“菜单也会执行这个函数
void Widget::on_exitButton_clicked() {
    if (!firstPlay) {//还没有打开视频，不需要刷新背景
        ReFreshBackground();
    }
    this->hide();//隐藏窗口
    WriteSetting();//写入设置
    qApp->exit(0);//退出
}

//加载视频文件
void Widget::LoadFile(const QString file) {
    QFile video(file);
    if (!video.exists()) {
        //文件不存在
        ui->fileLabel->setText("未打开文件");
        ui->playButton->setText(BUTTON_TEXT_PLAY);
        ui->playButton->setEnabled(false);
        path = "";
        ui->fileLabel->setToolTip(NULL);
        ui->fileLabel->setCursor(Qt::ArrowCursor);//默认鼠标样式
        return;
    }
    QFileInfo fi = QFileInfo(path);//文件信息
    this->ui->fileLabel->setText("正在加载:" + fi.fileName());//文件Label显示文件名
    path = file;
    if (firstPlay) {//是否是第一次播放
        HWND hwnd = (HWND) videoWidget.winId();//获取视频窗体的句柄
        if(!SetBackground(hwnd)){//把视频窗体设置成背景窗体的子窗体
            QMessageBox::information(this,"错误","无法获取背景窗体的句柄.");
            ui->fileLabel->setText("未打开文件");
            ui->playButton->setText(BUTTON_TEXT_PLAY);
            ui->playButton->setEnabled(false);
            path = "";
            ui->fileLabel->setToolTip(NULL);
            ui->fileLabel->setCursor(Qt::ArrowCursor);//默认鼠标样式
            return;
        }
        videoWidget.setWindowFlags(Qt::FramelessWindowHint);
        videoWidget.setAspectRatioMode(Qt::IgnoreAspectRatio);
        videoWidget.showFullScreen();
        list = new QMediaPlaylist;
        firstPlay = false;
    }
    //清理原有的播放列表，加入视频
    list->clear();
    list->addMedia(QMediaContent(QUrl::fromLocalFile(file)));
    list->setPlaybackMode(QMediaPlaylist::CurrentItemInLoop);//循环播放
    player.setPlaylist(list);
    player.setVideoOutput(&videoWidget);//设置输出窗体
    player.play();
    ui->playButton->setText(BUTTON_TEXT_PAUSE);
    action_play->setText(BUTTON_TEXT_PAUSE);
    ui->playButton->setEnabled(true);
    action_play->setEnabled(true);
    ui->fileLabel->setText("正在播放:" + fi.fileName());
    ui->fileLabel->setToolTip(path.replace("/", "\\"));
    ui->fileLabel->setCursor(Qt::PointingHandCursor);//“指向”鼠标样式
    ui->playButton->setEnabled(true);
}

//读取设置
void Widget::ReadSetting() {
    QFile file("setting");//设置文件，不需要后缀
    bool n = false;//是否加载上一次视频
    int v = 100;//音量
    if (file.open(QIODevice::ReadOnly)) {//文件存在
        QDataStream input(&file);
        input >> n >> v >> path;//读取
    }
    file.close();
    ui->checkBox_2->setChecked(n);
    ui->volumeSlider->setValue(v);
    if(!n) path = "";
}

//写入设置
void Widget::WriteSetting() {
    QFile file("setting");
    if (file.open(QIODevice::WriteOnly)) {
        QDataStream output(&file);
        output << ui->checkBox_2->isChecked() << ui->volumeSlider->value() << path;
    }
    file.close();
}

//设置开机自启，flag表示是否开机自启
void Widget::AutoRun(bool flag) {
    QString appPath = QApplication::applicationFilePath();
    appPath = appPath.replace("/", "\\");
    //打开注册表
    QSettings *reg = new QSettings(
            HKEY_AUTORUN,//宏定义，自启动的注册表位置，详细内容在头文件support.h里
            QSettings::NativeFormat);
    QString val = reg->value(HKEY_NAME).toString();//根据HKEY_NAME获取键值
    if (flag) {//打开开机自启
        if (!val.startsWith(appPath)) {//键值不是本程序地址或者不存在，则写入键值
            reg->setValue(HKEY_NAME, appPath + HKEY_PARAMETER);
        }
        QString v = reg->value(HKEY_NAME).toString();//读取刚刚写入的键值
        if (!v.startsWith(appPath)) {//写入失败
            ui->checkBox_1->setChecked(false);
            QMessageBox::warning(this, "拒绝访问", "添加注册表失败.", QMessageBox::Ok, QMessageBox::Ok);
        }
    } else {//关闭开机自启
        reg->remove(HKEY_NAME);//移除键值
        QString v = reg->value(HKEY_NAME).toString();
        if (v != "") {//键值仍然存在，移除失败
            ui->checkBox_1->setChecked(true);
            QMessageBox::warning(this, "拒绝访问", "移除注册表失败.", QMessageBox::Ok, QMessageBox::Ok);
        }
    }
    reg->deleteLater();//延迟删除
}

//开机自启checkbox点击事件
void Widget::on_checkBox_1_clicked() {
    AutoRun(ui->checkBox_1->isChecked());
}

//音量滑块值改变事件
void Widget::on_volumeSlider_valueChanged(int value) {
    //音量滑块的范围为0~1000,音量有效值是0~100，设置1000是为了减小卡顿感觉
    value = (value + 5) / 10;//四舍五入除以10
    ui->volumeLabel->setText(QString::number(value));
    if (value > 50 && VolumeNowPic != 2) {//高音量
        VolumeNowPic = 2;
        ui->volumePic->setStyleSheet(VOLUME_HIGH);
    } else if (value > 0 && value < 50 && VolumeNowPic != 1) {//低音量
        ui->volumePic->setStyleSheet(VOLUME_LOW);
        VolumeNowPic = 1;
    } else if (value == 0 && VolumeNowPic != 0) {//关闭音量
        ui->volumePic->setStyleSheet(VOLUME_OFF);
        VolumeNowPic = 0;
    }
    player.setVolume(value);//设置音量
}

//音量滑块鼠标释放事件
void Widget::on_volumeSlider_sliderReleased() {
    //当滑块位置在999时，此时音量是100，当用户释放鼠标后自动把滑块位置设置成1000
    ui->volumeSlider->setValue(player.volume() * 10);
}

//“关于”按钮点击事件
void Widget::on_aboutButton_clicked() {
    about.show();
}

//刷新背景，执行ReFreshBackground.exe
void Widget::ReFreshBackground() {
    WinExec(OPEN_REFRESHBAKGROUND_FILE_PATH, 0);//宏定义，在头文件support.h里面
}

//设置开机自启checkbox的checked
void Widget::setAutoRun(bool isAutoRun) {
    //当用户在“关于”窗口里清理了注册表后，需要实时调整“开机自启”checkbox的checked
    ui->checkBox_1->setChecked(isAutoRun);
}

//播放速度滑块鼠标释放事件
void Widget::on_rateSlider_sliderReleased() {
    int rate = (ui->rateSlider->value() + 25) / 50;//24舍25入除以50，此时rate的范围是1~20
    ui->rateSlider->setValue(rate * 50);//乘上50，校准滑块位置
    sliderEnable = true;//value监听可用
    on_rateSlider_valueChanged(ui->rateSlider->value());//执行一次value监听事件，修改player的播放速度
}

//播放速度滑块value改变事件
void Widget::on_rateSlider_valueChanged(int value) {
    //范围是50~1000，对应速度0.1~2.0，默认为1.0，设置1000是为了减小卡顿感
    int rate = (value + 25) / 50;//24舍25入除以50，此时rate的范围是1~20
    ui->rateLabel->setText(QString::number(rate / 10.0, 'f', 1));//显示数值的Label，把rate除以10并取小数点后一位
    if (sliderEnable) {//如果value监听可用
        //在修改播放速度时会有明显黑屏，为了防止过多黑屏影响视觉感受，当用户滑动滑块时不改变速度，当用户释放鼠标时再改变
        //当用户使用滚轮，或者点击滑动栏，触发stepadd或stepsub时，需要改变播放速度
        player.setPlaybackRate(rate / 10.0);//设置播放速度
    }
}

//速度滑块点击事件
void Widget::on_rateSlider_sliderPressed() {
    sliderEnable = false;//value监听不可用，防止过多黑屏，当用户使用滚轮时不触发本事件，因此value监听有效
}

//判断是否打开开机自启
bool isAutoRun() {
    QString appName = QApplication::applicationName();
    QString appPath = QApplication::applicationFilePath();
    appPath = appPath.replace("/", "\\");
    QSettings *reg = new QSettings(
            HKEY_AUTORUN,//宏定义，在头文件support.h里面
            QSettings::Registry64Format);
    //如果注册表键值就是本程序的地址，表示打开了开机自启
    QString val = reg->value(appName).toString();
    return val.startsWith(appPath);
}

//将child窗体设置成背景窗体的子窗体
bool SetBackground(HWND child) {
    HWND background = GetBackground();
    if(background != 0){
        SetParent(child, GetBackground());
        return true;
    }
    return false;
}

//获取背景窗体句柄
HWND GetBackground() {
    //背景窗体没有窗体名，但是知道它的类名是workerW，且有父窗体Program Maneger，所以只要
    //遍历所有workW类型的窗体，逐一比较它的父窗体是不是Program Manager就可以找到背景窗体
    HWND hwnd = FindWindowA("progman", "Program Manager");
    HWND worker = NULL;
    do {
        worker = FindWindowExA(NULL, worker, "workerW", NULL);
        if (worker != NULL) {
            char buff[200] = {0};
            int ret = GetClassNameA(worker, (PCHAR) buff, sizeof(buff) * 2);
            if (ret == 0) {
                return NULL;
            }
        }
        if (GetParent(worker) == hwnd) {
            return worker;//返回结果
        }
    } while (worker != NULL);
    //没有找到
    //发送消息生成一个WorkerW窗体
    SendMessage(hwnd,0x052C,0,0);
    //重复上面步骤
    do {
        worker = FindWindowExA(NULL, worker, "workerW", NULL);
        if (worker != NULL) {
            char buff[200] = {0};
            int ret = GetClassNameA(worker, (PCHAR) buff, sizeof(buff) * 2);
            if (ret == 0) {
                return NULL;
            }
        }
        if (GetParent(worker) == hwnd) {
            return worker;//返回结果
        }
    } while (worker != NULL);
    return NULL;
}
